package com.andy.myFramework.mvc.servlet;

import com.andy.myFramework.ioc.BeanFactory;
import com.andy.myFramework.ioc.impl.DefaultBeanFactory;
import com.andy.myFramework.mvc.DefaultHandlerFactory;
import com.andy.myFramework.mvc.HandlerFactory;
import com.andy.myFramework.mvc.pojo.Handler;
import com.andy.myFramework.util.JsonUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class DispatcherServlet extends HttpServlet {

    private Properties properties = new Properties();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            //开始寻找controller并调用
            Object resut = null;
            String url = req.getRequestURI();
            //从容器上下文获取handlerFactory
            ServletContext servletContext = getServletContext();
            HandlerFactory handlerFactory = (HandlerFactory)servletContext.getAttribute("handlerFactory");
            Handler handle = handlerFactory.getHandle(url);
            //如果有mapping的url则调用
            if(handle!=null){
                resut = doHandleMethod(req,resp,handle);
            }

            //输出结果
            resp.setContentType("application/json; charset=utf-8");
            PrintWriter out = resp.getWriter();
            out.print(JsonUtils.object2Json(resut));
            out.flush();
            out.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 执行handle的方法
     * @param req
     * @param resp
     * @param handle
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private Object doHandleMethod(HttpServletRequest req, HttpServletResponse resp,Handler handle) throws InvocationTargetException, IllegalAccessException {
        //1-权限校验
        Set<String> securities = handle.getSecurities();
        String username = req.getParameter("username");
        if(securities.size()>0 && !securities.contains(username)){
            return "用户权限不足";
        }

        //2-真正开始调用
        //获取对象和方法
        Object controller = handle.getController();
        Method method = handle.getMethod();
        Map<String, Integer> paramIndexMapping = handle.getParamIndexMapping();
        //构造入参对象args
        Object[] args = new Object[paramIndexMapping.size()];
        for (Map.Entry<String, Integer> entry : paramIndexMapping.entrySet()) {
            String paramName = entry.getKey();
            Integer paramIndex = entry.getValue();
            if("HttpServletRequest".equals(paramName)){
                args[paramIndex] = req;
                continue;
            }
            if("HttpServletResponse".equals(paramName)){
                args[paramIndex] = resp;
                continue;
            }
            args[paramIndex] = req.getParameter(paramName);
        }

        //反射调用controller
        return method.invoke(controller,args);
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        try {
            //1-加载配置文件 springmvc.properties
            String contextConfigLocation = config.getInitParameter("contextConfigLocation");
            doLoadConfig(contextConfigLocation);

            //2-创建ioc工厂
            BeanFactory beanFactory = new DefaultBeanFactory();
            String scanClassPath = properties.getProperty("scanPackage");
            beanFactory.initBeanFactory(scanClassPath);
            //放入容器上下文
            ServletContext servletContext = getServletContext();
            servletContext.setAttribute("beanFactory",beanFactory);

            //3-创建mvc的Handler工厂
            HandlerFactory handlerFactory = new DefaultHandlerFactory();
            handlerFactory.initHandlerFactory(beanFactory.getSingletons());
            //放入容器上下文
            servletContext.setAttribute("handlerFactory",handlerFactory);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 加载配置文件
    private void doLoadConfig(String contextConfigLocation) {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
